<?php

/**
 *
 *
 * @version $Id$
 * @copyright 2013
 */

namespace com\org\web\tpl\utils {
	class Reflector {
		private $reflector = NULL;
		private $interfaceNames = NULL;
		private $obj = NULL;

		public function __construct(&$obj) {
			$this->obj = $obj;
			$this->reflector = new ReflectionClass($this->obj);
		}

		public function inherit($name) {
			if (!isset($this->interfaceNames))
				$this->interfaceNames = $this->reflector->getInterfaceNames();
			foreach($this->interfaceNames as $interface) {
				if (strcmp($name, $interface) === 0)
					return TRUE;
			}

			return FALSE;
		}

		public function extend($name) {
			return FALSE;
		}

		public function propertyValue($propertyName) {
			$property = $this->reflector->getProperty($propertyName);
			return $property->getValue($this->obj);
		}

		public function invoke($methodName, $args) {
			$array = array();
			if (is_array($args))
				$array = $args;
			else
				$array[0] = $args;
			$method = $this->reflector->getMethod($methodName);
			return $method->invokeArgs($this->obj, $array);
		}

		public function isPrimitive($obj) {
			if (is_object($obj))
				return FALSE;
			return TRUE;
		}

		public function getProperties($filter = 0) {
			if ($filter <= 0)
				$filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_STATIC;
			$properties = $this->reflector->getProperties($filter);
		}

		public function __destruct() {
			if (isset($this->obj))
				unset($this->obj);
			if (isset($this->reflector))
				unset($this->reflector);
			if (isset($this->interfaceNames))
				unset($this->interfaceNames);
		}

		public static function implement(&$obj, $name) {
			$reflector = new ReflectionClass($obj);
			$interfaces = $reflector->getInterfaceNames();
			foreach($interfaces as $interface) {
				if (strcmp($name, $interface) === 0)
					return TRUE;
			}

			return FALSE;
		}

		public static function invokeMethod(&$obj, $methodName, $args) {
			$array = array();
			if (is_array($args))
				$array = $args;
			else
				$array[0] = $args;
			$method = new \ReflectionMethod($obj, $methodName);
			$method->setAccessible(true);
			return $method->invokeArgs($obj, $array);
		}

		public static function getPropertyValue(&$obj, $propertyName) {
			$property = new ReflectionProperty($obj, $propertyName);
			return $property->getValue($obj);
		}

		public static function invokeStaticMethod($className, $methodName, $args) {
			$array = array();
			if (is_array($args))
				$array = $args;
			else
				$array[0] = $args;
			$reflectionMethod = new ReflectionMethod($className, $methodName);
			return $reflectionMethod->invokeArgs(NULL, $array);
		}

		public static function getStaticPropertyValue($className, $propertyName) {
			$reflectionClass = new ReflectionClass($className);
			return $reflectionClass->getProperty($propertyName)->getValue();
		}

		public static function invokeTrail($data) {
			$object = NULL;
			if (!String::isEmpty($data["class"]) && strlen(trim($data["class"]))) {
				$trail = $data["trail"];
				$fist = $trail[0];
				if ($first["property"] === TRUE) {
					$var = TemplateVarParser::parse($first["info"]);
					$object = self::getStaticPropertyValue($data["class"], $var["name"]);
					$object = self::invokeArray($object, $var["indice"]);
				}
				else {
					$object = self::invokeStaticMethod($data["class"], $first["info"]["name"], $first["info"]["args"]);
				}

				if (count($trail) > 1) {
					$trail = array_slice($trail, 1);
					$object = self::invokeSubTrail($object, $trail);
				}
			}
			else {
				$trail = $data["trail"];
				$object = $trail[0];
				$trail = array_slice($trail, 1);
				$object = self::invokeSubTrail($object, $trail);
			}

			return $object;
		}

		public static function invokeArray($array, $indice) {
			if (!is_array($array) || !isset($indice))
				return $array;
			foreach($indice as $index)
				$array = $array[$index];
			return $array;
		}

		private static function invokeSubTrail($object, $trail) {
			if (!is_object($object))
				return $object;
			$reflector = NULL;
			foreach($trail as $callee) {
				if ($callee["property"] === TRUE) {
					$var = TemplateVarParser::parse($callee["info"]["name"]);
					$method = "get" . $var["name"];
					if(method_exists($object, $method))
						$object = self::invokeMethod($object, $method, array());
					else
						$object = self::getPropertyValue($object, $var["name"]);
					$object = self::invokeArray($object, $var["indice"]);
				}
				else {
					$object = self::invokeMethod($callee["info"]["name"], $callee["info"]["args"]);
				}
			}

			return $object;
		}
	}
}
?>